using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Evolution.Engine.Interfaces;
using Evolution.Engine.Managers;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.ObjectModel;
using Evolution.Engine.Physics;

namespace Evolution.Engine
{
    /// <summary>
    /// This is the base for any object that will make itself into the 3d scene in any form or facion.
    /// </summary>
    public class BaseObject
    {
        protected string _Name;
        protected Vector3 _Position;
        protected Vector3 _Scale;
        protected Quaternion _Rotation;
        protected string _ScriptAsset;
        protected IScript Script { get { return string.IsNullOrEmpty(_ScriptAsset) ? null : ScriptManager.Instance.Get<IScript>(_ScriptAsset, "Scripts"); } }
        protected bool _AlwaysFacingPlayer;
        protected string _Shader;
        protected bool _Visible;
        protected BoundingBox _Bounds;
        protected Collection<BaseObject> _Children = new Collection<BaseObject>();
        protected BoundingSphere _BoundingSphere;
        protected bool _AlphaCheck;
        protected PhysicsObject _PhysicsObject;
        protected float _MaxVelocity = 1f / 10f;

        public float MaxVelocity { get { return _MaxVelocity; } set { _MaxVelocity = value; } }
        public PhysicsObject PhysicsObject { get { return _PhysicsObject; } }
        public BoundingSphere BoundingSphere { get { return _BoundingSphere; } set { _BoundingSphere = value; } }
        public Collection<BaseObject> Children { get { return _Children; } set { _Children = value; } }
        public BoundingBox Bounds { get { return _Bounds; } set { _Bounds = value; } }
        public bool Visible { get { return _Visible; } set { _Visible = value; } }
        public string Shader { get { return _Shader; } set { _Shader = value; } }
        public bool AlwaysFacingPlayer { get { return _AlwaysFacingPlayer; } set { _AlwaysFacingPlayer = value; } }
        public Quaternion Rotation { get { return _Rotation; } set { _Rotation = value; } }
        public Vector3 Scale { get { return _Scale; } set { _Scale = value; } }
        public Vector3 Position { get { return _Position; } set { _Position = value; } }
        public string Name { get { return _Name; } set { _Name = value; } }


        public BaseObject(string Name)
        {
            _Position = new Vector3(0, 0, 0);
            _Scale = new Vector3(1, 1, 1);
            _Rotation = new Quaternion(0, 0, 0, 1);
            _Name = Name;
            _AlwaysFacingPlayer = false;
            _Visible = true;
            _AlphaCheck = false;
            _PhysicsObject = new PhysicsObject(this);
        }
        public void SetShader(string asset)
        {
            _Shader = asset;
        }
        public void SetScript(string asset)
        {
            _ScriptAsset = asset;
        }
        public void Draw(GameTime gameTime)
        {
            if (Script != null) Script.Draw(gameTime);
            if (this is IHasMaterial) ((IHasMaterial)this).SetMaterialProperties();

            if (this is IRenderable)
            {
                Shader shader = ShaderManager.Instance.GetShader(_Shader);
                shader.SetParameters(this);

                shader.Effect.Begin();
                foreach (EffectPass pass in shader.Effect.CurrentTechnique.Passes)
                {
                    pass.Begin();

                    ((IRenderable)this).Render(gameTime);

                    pass.End();
                }
                shader.Effect.End();
            }

            if (this is ITerrainDraw) ((ITerrainDraw)this).TerrainDraw(gameTime);
            if (this is IChildRenderer) ((IChildRenderer)this).RenderChildren(gameTime);

            if (Children.Count > 0)
            {
                foreach (BaseObject child in Children)
                    child.Draw(gameTime);
            }
        }
        public virtual void Update(GameTime gameTime)
        {
            if (Script != null) Script.Update(gameTime);
            if (this is Evolution.Engine.Interfaces.IUpdateable) ((Evolution.Engine.Interfaces.IUpdateable)this).Update(gameTime);

            if (Children.Count > 0)
            {
                foreach (BaseObject child in Children)
                    child.Update(gameTime);
            }
        }
        public virtual void LoadContent()
        {
            if (Script != null) Script.Load();
            if (this is ILoadable) ((ILoadable)this).LoadContent();
        }

        public Matrix World
        {
            get
            {
                if (!_AlwaysFacingPlayer)
                {
                    return MatrixScale * MatrixRotation * MatrixTranslation;
                }
                else
                {
                    return MatrixScale * CameraManager.Instance.ActiveCamera.MatrixInverseRotation * MatrixTranslation;
                }
            }
        }
        public Matrix MatrixRotation { get { return Matrix.CreateFromQuaternion(_Rotation); } }
        public Matrix MatrixTranslation { get { return Matrix.CreateTranslation(_Position); } }
        public Matrix MatrixScale { get { return Matrix.CreateScale(_Scale); } }
    }
}
